{-
    SetOps.hs: Set theoretic operation functions.
    ----------------------------------------------------------------------------
    Version: 1.0alpha1
    Author:  Christopher Granade (cgranade@gmail.com)
    ----------------------------------------------------------------------------
    This file is a part of the Die Rolling Analysis Toolkit (DRAT) project.
    http://drat.googlecode.com/
    ----------------------------------------------------------------------------
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 or 3 of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    ----------------------------------------------------------------------------
    (c) 2007 Christopher E. Granade
-}
module SetOps where
    
    selfcross        :: (Integral b) => [a] -> b -> [[a]]
    selfcross xs 1   =  [[x] | x <- xs]
    selfcross xs 2   =  crossToList xs xs
    selfcross xs pow =  crossToListRep xs (selfcross xs (pow - 1))
    
    cross             :: [a] -> [b] -> [(a, b)]
    cross xs ys       =  [(x, y) | x <- xs, y <- ys]
    
    crossToList       :: [a] -> [a] -> [[a]]
    crossToList xs ys =  [[x, y] | x <- xs, y <- ys]
    
    crossToListRep        :: [a] -> [[a]] -> [[a]]
    crossToListRep xs yss =  [x:ys | x <- xs, ys <- yss]
    
    flattenTuple   :: ((a, b), c) -> (a, b, c)
    flattenTuple t =  (fst $ fst t, snd $ fst t, snd t)
    
    -- Given a list, generates a list of the permutations of the elements
    -- of the list.
    permute :: [a] -> [[a]]
    permute [x] = [[x]]
    permute xs =
        let x = head xs
            pxs = permute (drop 1 xs)
            ns = [0..(length $ head pxs)]
        in [ insertBefore x n px | n <- ns, px <- pxs ]
            
    -- Inserts the given element before a specific position in the given list.
    insertBefore :: a -> Int -> [a] -> [a]
    insertBefore a w as = (take w as)  ++ a:(drop w as)